#ifndef PROCESS_H
#define PROCESS_H
#include <memory>
#include <iostream>

using namespace std;

class Process;
typedef shared_ptr<Process> StrongProcessPtr;
typedef weak_ptr<Process> WeakProcessPtr;

class Process
{
	friend class ProcessManager;

public:
	enum State
	{
		// Uninitialized
		UNINITIALIZED = 0,
		REMOVED, // removed from process list but not destroyed
		// Alive
		RUNNING,
		PAUSED,
		// Dead
		SUCCEEDED,
		FAILED,
		ABORTED
	};

private:
	State m_state;
	StrongProcessPtr m_pChild;

public:
	// Construction
	Process(void);
	virtual ~Process();

protected:
	// Interfaces (will be overridden)
	virtual void VOnInit(void) {m_state = RUNNING;}
	virtual void VOnUpdate(unsigned long deltaMs) = 0;
	virtual void VOnSuccess(void){}
	virtual void VOnFail(void){}
	virtual void VOnAbort(void){}

public:
	// functions for ending the process
	inline void Succeed(void);
	inline void Fail(void);

	// functions for pausing the process
	inline void Pause(void);
	inline void UnPause(void);

	// accessors
	State GetState(void) const {return m_state;}
	bool IsAlive(void) const {return (m_state == RUNNING || m_state == PAUSED);}
	bool IsDead(void) const {return (m_state == SUCCEEDED || m_state == FAILED || m_state == ABORTED);}
	bool IsRemoved(void) const {return m_state == REMOVED;}
	bool IsPaused(void ) const {return m_state == PAUSED;}

	// child functions
	inline void AttachChild(StrongProcessPtr pChild);
	StrongProcessPtr RemoveChild(void); // release ownership of child process
	StrongProcessPtr PeekChild(void) {return m_pChild;} // does not release ownership of child

private:
	void SetState(State newState) {m_state = newState;}
	};

//---------------------------------------------------------------------------------------------------------------------
// Inline function definitions
//---------------------------------------------------------------------------------------------------------------------
inline void Process::Succeed(void)
{
	m_state = SUCCEEDED;
}

inline void Process::Fail(void)
{
	m_state = FAILED;
}

inline void Process::AttachChild(StrongProcessPtr pChild)
{
	if (m_pChild)
		m_pChild->AttachChild(pChild);
	else
		m_pChild = pChild;
}

inline void Process::Pause(void)
{
	if (m_state == RUNNING)
		m_state = PAUSED;
	else
		cout << "Attempting to pause a process that isn't running" << endl;
}

inline void Process::UnPause(void)
{
	if (m_state == PAUSED)
		m_state = RUNNING;
	else
		cout << "Attempting to unpause a process that isn't paused" << endl;
}

#endif